function KeyboardPlot(block)
%Main Program to Plot Keyboard Graphics
setup(block);


%% load parameters
warning('off','MATLAB:dispatcher:InexactMatch');
parameters;


%% endfunction

function setup(block)
% Register number of ports
block.NumInputPorts  = 1;
block.NumOutputPorts = 1;%Target Counter

% Setup port properties to be inherited or dynamic
block.SetPreCompInpPortInfoToDynamic;
block.SetPreCompOutPortInfoToDynamic;

% Override input port properties
block.InputPort(1).Dimensions  = 24; % 2 Times + 22 Glove
block.InputPort(1).DatatypeID  = 0;  % double
block.InputPort(1).Complexity  = 'Real';
block.InputPort(1).DirectFeedthrough = true;

% Override output port properties
block.OutputPort(1).Dimensions  = 1;
block.OutputPort(1).DatatypeID  = 0;
block.OutputPort(1).Complexity  = 'Real';

% Register parameters
block.NumDialogPrms     = 0;

% Register sample times
%  [0 offset]            : Continuous sample time
%  [positive_num offset] : Discrete sample time
%  [-1, 0]               : Inherited sample time
%  [-2, 0]               : Variable sample time
block.SampleTimes = [-1 0];


block.RegBlockMethod('PostPropagationSetup',    @DoPostPropSetup);
block.RegBlockMethod('InitializeConditions', @InitializeConditions);
block.RegBlockMethod('Start', @Start);
block.RegBlockMethod('Outputs', @Outputs);     % Required
block.RegBlockMethod('Update', @Update);
block.RegBlockMethod('Derivatives', @Derivatives);
block.RegBlockMethod('Terminate', @Terminate); % Required

%% end setup


function DoPostPropSetup(block)
%%%%%%%%%%%%%%%%%%%%%%%%%
%C. Velocity Detection parameters
%%%%%%%%%%%%%%%%%%%%%%%%%
global res fontSize xFrame yFrame;
global m n scrambled fontsize
global PosTarget
global pK pR pF

global FLAG_HIT FLAG_STARTED FLAG_FBOFF

global isInsideTarget isInsideInitPos
global iScreen
global tBackStart tBackEnd tGoStart tHitStart tFBStart tFBEnd

global hfig hax hrect hletter htext pt
global A OFFSET
global bigloop glovedata_prev time_prev
global insthandvel JITTER NUMFRAMES
global TYPEDTEXT
global stationaryflag movingflag highlightedflag outofbounds_flag NEWKEYPRESS startflag closeflag OUTOFBOUNDSALLOWED
global TARGETS T
global T_IN_TARGET IN_OLD_TARGET CURR_TARG_HIT FLAG_BACK TIME_AFTER_KEYPRESS TRANSITION_KEY
global CURSOR_DURING_TRIAL CURSOR_AFTER_TRIAL KEY_DURING_TRIAL KEY_AFTER_TRIAL TEXTFLAG SCOREFLAG
global scorecard TOTSCORE TOTPOSSIBLESCORE SCORE_RECORD
global Topoutofbounds Leftoutofbounds Rightoutofbounds Botoutofbounds
global Topflag Leftflag Rightflag Botflag
global TARG_KEYS PUSH_KEYS
global T_IN_KEY T_OUT_KEY MT
global highlightrect
global XCOORD YCOORD IND_IN_KEY IND_OUT_KEY
global  A_mult   A_AMA OFFSETx OFFSETy OFFSETxy Key_feedback


%% Open Cogent workspace
config_log('cogent_log.txt');
config_mouse;
config_keyboard(1,res,'nonexclusive');
config_display(1,res);
cgloadlib
start_cogent


%======================================================================
%A. Keyboard parameters
%======================================================================
TYPEDTEXT=[];
closeflag = 0;

%======================================================================
%B. Glove parameters
%======================================================================
NUMCHANNELS = 19;
glovedata_prev = zeros(NUMCHANNELS,1);
time_prev = 0;
XCOORD=[];YCOORD=[];

%======================================================================
%C. Velocity Detection parameters
%======================================================================
JITTER = 2;
NUMFRAMES = 40;
insthandvel = ones(1,NUMFRAMES); %Logical Array that indicates whether instantaneous hand velocity is below JITTER

%======================================================================
%D. Status Flags
%======================================================================
highlightedflag = 0;    %Indicates if a key is highlighted on screen
stationaryflag = 0;     %Indicates if hand is stationary
movingflag = 0;         %Indicates if cursor has started moving again
startflag = 0;          %Indicates when data collection starts
outofbounds_flag = 0;   %Indicates if cursor is stationary, but out of bounds
NEWKEYPRESS = 0;        %Indicates if a new key has just been pressed

CURR_TARG_HIT = 0;      %Indicates if the target key and the current key are the same
SET_NEXT_TARG = 1;      %Indicates that is time to update the next target

IN_OLD_TARGET   = 0;    %Indicates if the cursor is on the same character (prevents repeating of same character)
TRANSITION_KEY  = 0;    %Indicates if a new target is about to be displayed (This process cannot be interrupted by movement of the cursor)

%======================================================================
% Flags shared with Update()
%======================================================================
FLAG_BACK       = 0;    % 1: cursor is back to the center, 0: hasn't been back yet
FLAG_STARTED    = 0;    % 1: a trial has started, 0: hasn't started yet
FLAG_HIT        = 0;    % 1: hit, -1: out of bounds, 0: moving
FLAG_FBOFF		= 0;	% 1: feedback off, 0: feedback on

%======================================================================
% Variables shared with Update()
%======================================================================
isInsideTarget  = 0;    % 1: cursor is inside of the target, 0: outside of the target
isInsideInitPos = 0;    % 1: cursor is inside of the init position, 0: outside of the initial position
tHitStart = 0;    
iScreen         = 3;    % Screen #, 0: ready, 1: go, 2: done, 3: back
tBackStart      = 0;    % time at which the cursur first came back to the start position
tGoStart        = 0;    % time at which a trial begins
tFBStart        = 0;    % time at which the trial ends and feedback starts

%======================================================================
%E. Time Counters
%======================================================================
bigloop = 0;            %Counts every iteration of the simulation
T_IN_TARGET = 0;        %Counts time while the cursor is inside the target (used to trigger key highlight)
TIME_AFTER_KEYPRESS = 0; %Counts time after key press (used to cue the next target)

%load A matrix from TDS file
A=A_mult*A_AMA;
OFFSET=OFFSETxy;

%======================================================================
%H. Targets, Target counter, and Scoring
%======================================================================
T = 1;

TOTSCORE = 0;
TOTPOSSIBLESCORE = 0;
SCORE_RECORD=[];

TARG_KEYS=[];
PUSH_KEYS=[];

T_IN_KEY = [];
T_OUT_KEY = [];
MT = [];
IND_IN_KEY=[];
IND_OUT_KEY=[];

cgpencol(1,1,1);
cgfont('Arial',60);
cgtext(['Waiting for a signal from CyberGlove...'],0,0);
cgflip(0,0,0);


%% end PostPropSetup

function InitializeConditions(block)



%% end InitializeConditions

function Start(block)

%% endfunction

function Outputs(block)
%Output which target it is currently in
global T

block.OutputPort(1).Data = T; %Output how many targets have been completed

%% end Outputs

function Update(block)
global res fontSize xFrame yFrame Gain;
global mouseSize mouseThick diameter
global nTrial nTask TaskColor Task
global PosTarget
global pK pR pF
global schedTrn schedPos schedFB 
global fLogTraj fLogTrial
global X Y Xnew Ynew Xtar Ytar

global FLAG_HIT FLAG_BACK FLAG_STARTED FLAG_FBOFF

global isInsideTarget isInsideInitPos
global iScreen
global tBackStart tBackEnd tGoStart tGoEnd tHitStart tHitEnd
global tFBStart tFBEnd
global logHit logXc logYc logXt logYt logMT logTask

global m n scrambled fontsize letters
global hfig hax hrect hletter htext pt
global A OFFSET
global bigloop glovedata_prev time_prev
global insthandvel JITTER NUMFRAMES
global TYPEDTEXT
global stationaryflag movingflag highlightedflag outofbounds_flag NEWKEYPRESS startflag closeflag
global TARGETS T targ_col targ_row
global T_IN_TARGET IN_OLD_TARGET CURR_TARG_HIT outofbounds TIME_AFTER_KEYPRESS TRANSITION_KEY
global CURSOR_DURING_TRIAL CURSOR_AFTER_TRIAL 
global scorecard TOTSCORE TOTPOSSIBLESCORE
global TARG_KEYS PUSH_KEYS
global cputime glovesignals mvt_start mvt_end T_IN_KEY T_OUT_KEY MT
global insthandvel NUMFRAMES
global highlightrect
global XCOORD YCOORD IND_IN_KEY IND_OUT_KEY
global NO_FB_TRIAL Key_feedback

%Iteration counter
bigloop = bigloop+1;
if T <= nTrial
    
    switch iScreen
        case 0
            %==============================================================
            % 0: Get Ready
            %==============================================================
            if tBackStart == 0
                tBackStart = tic;
                cgpencol(1,1,1);
                cgpenwid(2);
                cgrect(0, 0, mouseSize, mouseThick);
                cgrect(0, 0, mouseThick, mouseSize);
                cgflip(0,0,0);
            elseif toc(tBackStart)*1000 > tBackEnd
                % If the cursor have stayed for more than 1 s, change
                % the screen to the next.
                iScreen = 1;
                tBackStart = 0;
            end
        case 1
            %==============================================================
            % 1: Go
            %==============================================================
            if tGoStart == 0
                % Draw the target only at the beginning of each trial                
                tGoStart = tic;
                Task     = schedTrn(T);                         % Selected Target and Task
                [Xtar, Ytar] = drawTarget(Task, schedPos(T));   % Set the Positions randomly
				IND_IN_KEY = [IND_IN_KEY, bigloop]; 
			end

            cgdrawsprite(62,0,0);
            
            % Read Signals from Glove 
            % - 24 Channels - 2 Time Channels + 22 Glove Channels
            time = block.InputPort(1).Data(1); % Glove Time
            cputime = block.InputPort(1).Data(2); %CPU Time
            glovesignals = block.InputPort(1).Data(3:21); %Glove signals excluding last 3 channels

            % Multiply glove signals by matrix A to get x,y coordinates of cursor
            % - positions returned by the glove are between 0 ~ 5
            COORD = A*glovesignals + OFFSET;
            XCOORD(bigloop) = COORD(1); 
            YCOORD(bigloop) = COORD(2);
            X = Gain*(COORD(1)-2.5);        
            Y = Gain*(COORD(2)-2.5);

            % Display the cursor
            [Xnew Ynew FLAG_FBOFF] = drawCursor(Task, X, Y, schedFB(T), FLAG_FBOFF);

            if toc(tGoStart)*1000 > tGoEnd
                % If the cursor have stayed for more than 3 s, change
                % the screen to the next.
                FLAG_HIT = -2;
            else    
                % Check if the cursor is out of bounds
                if (Xnew >= xFrame) || (Ynew >= yFrame) || (Xnew <= -xFrame) || (Ynew <= -yFrame)
                    FLAG_HIT = -1;
                    cgpencol(1,1,1);
                    cgfont('Arial',60);
                    cgtext(['Out of bounds'],0,300);
                    cgflip(0,0,0);
                else
                    % The cursor is not out of bounds.
                    distToTarget = norm([Xnew-Xtar, Ynew-Ytar]);
                    if distToTarget < diameter/2
                        if isInsideTarget == 0
                            isInsideTarget = 1;
                            tHitStart = tic;
                        else
                            if toc(tHitStart)*1000 > tHitEnd
                                FLAG_HIT = 1;
                            end            
                        end
                    else
                        isInsideTarget = 0;
                    end
                end
            end
            
            if FLAG_HIT ~= 0
                % Store data for this trial
                logHit(T) = FLAG_HIT;
                logXc(T) = Xnew;
                logYc(T) = Ynew;
                logXt(T) = Xtar;
                logYt(T) = Ytar;
                logMT(T) = toc(tGoStart)*1000;
                logTask(T) = Task;
				IND_OUT_KEY = [IND_OUT_KEY, bigloop];				
                
                % Move to the next trial
                iScreen  = 2;
                tGoStart = 0;
                FLAG_HIT = 0;
				FLAG_FBOFF = 0;
            end    

        case 2
            %==============================================================
            % 2: Finish
            %==============================================================
             if tFBStart == 0
                tFBStart = tic;
                cgflip(0,0,0);
                switch res
                    case 3
                        cgmakesprite(64,1024,768,0,0,0);
                    case 5
                        cgmakesprite(64,1280,1024,0,0,0);
                end
                cgsetsprite(64)
                cgpencol( .5, .5, .5 );
                cgellipse(Xtar,Ytar,diameter,diameter,'f');
                cgpencol(1,1,1);
                cgpenwid(2);
                cgrect(Xnew, Ynew, mouseSize, mouseThick);
                cgrect(Xnew, Ynew, mouseThick, mouseSize);
                cgsetsprite(0)
                cgflip(0,0,0); 
          
             elseif toc(tFBStart)*1000 > tFBEnd
                % If the cursor have stayed for more than .5 s, change
                % the screen to the next.
                iScreen  = 3;
                tFBStart = 0;
                T = T + 1;
             end
             cgdrawsprite(64,0,0);
             cgflip(0,0,0);
        case 3
            %==============================================================
            % 3: Come back
            %==============================================================
            
            % Read Signals from Glove 
            % - 24 Channels - 2 Time Channels + 22 Glove Channels
            time = block.InputPort(1).Data(1);      % Glove Time
            cputime = block.InputPort(1).Data(2);   % CPU Time
            glovesignals = block.InputPort(1).Data(3:21); %Glove signals excluding last 3 channels

            % Multiply glove signals by matrix A to get x,y coordinates of cursor
            % - positions returned by the glove are between 0 ~ 5
            COORD = A*glovesignals + OFFSET;
            XCOORD(bigloop) = COORD(1); 
            YCOORD(bigloop) = COORD(2);
            X = Gain*(COORD(1)-2.5);        
            Y = Gain*(COORD(2)-2.5);

            distToInitPos = norm([X, Y]);
            if distToInitPos < diameter/2
                if isInsideInitPos == 0
                    isInsideInitPos = 1;
                    tHitStart = tic;
                else
                    InsideTime = toc(tHitStart);
                    if InsideTime*1000 > tHitEnd
                        FLAG_BACK = 1;
                    end            
                end
            else
                isInsideInitPos = 0;
            end

            % Display the cursor position as a circle
            cgpencol(1,1,1);
            cgpenwid(2);
            cgellipse(0,0,diameter,diameter,'f');

            % Display the circle showing how close the cursor is to the
            % center start position
            cgpencol(.5,.5,.5);
            cgpenwid(5);
            cgellipse(0,0,distToInitPos*2, distToInitPos*2);
            cgflip(0,0,0);
            
            if FLAG_BACK == 1
                iScreen  = 0;
                FLAG_BACK = 0;
            end      
    end
else
    %% Save trial data
    save(fLogTraj, 'XCOORD', 'YCOORD', 'IND_IN_KEY', 'IND_OUT_KEY');
    save(fLogTrial, 'logHit', 'logXc', 'logYc', 'logXt', 'logYt', ...
                    'logMT', 'logTask');

    %% Test has finished. Stop Cogent
    cgpencol(1,1,1);
    cgpenwid(2);
    cgrect(0,0,mouseSize,mouseThick);
    cgrect(0,0,mouseThick,mouseSize);
    cgflip(0,0,0);
    wait(2000);
    cgshut;
    stop_cogent;
end


%% end Update

function Derivatives(block)

%% end Derivatives

function Terminate(block)

%% end Terminate

